home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 7 / BBS in a Box - Macintosh - Volume VII (BBS in a Box) (January 1993).iso / Files / Tele / C / Comet2.1.3.cpt / Comet / textedit.c < prev    next >
Text File  |  1991-06-25  |  25KB  |  1,103 lines

  1. /*
  2.     Copyright Cornell University 1986.  All rights are reserved.
  3.     
  4.     scrinit.c contains scr_init, which initializes the screen and
  5.     create FONT bitmaps if needed (on the small-screen Mac),
  6.     and a  routine to save the screen location on exit.
  7.  
  8. */
  9.  
  10.  
  11.  
  12. #include    <em.h>
  13.  
  14. #include    <3270.h>
  15. #include    <h19.h>
  16. #include    <config.h>
  17. #include    <macdefs.h>
  18. #include    <cntldefs.h>
  19. #include    <rcodes.h>
  20.  
  21. #define SBARWIDTH    16            /* # pixels scroll bar width */
  22. #define TEXTINSET    6            /* exactly 80 characters fit */
  23.  
  24. CursHandle textcursor;         /* custom text beam */
  25.  
  26. pascal void        RepAction();
  27. pascal Boolean    ClickLoop();
  28.  
  29.         
  30. struct texts * textsp;            /* current text edit structure for tracking */
  31.  
  32. #ifdef USETEXTWINDOWS
  33.  
  34. textwinit()
  35. {
  36.     Rect viewrect;
  37.     Rect destrect;
  38.     Rect nullrect;
  39.     Rect sBarRect;
  40.  
  41.     textcursor = GetCursor(iBeamCursor);
  42.     
  43.     SetPort(emdp->textwindow);
  44.  
  45.     TextFont(emdp->normfont);
  46.     TextSize(emdp->fontsize);
  47.     
  48.     /* set up text edit record */
  49.     setteview(&viewrect);
  50.     settedest(&destrect);
  51.     
  52.     emdp->texthand = TENew(&destrect, &viewrect);
  53.     (*emdp->texthand)->txFont = emdp->normfont;
  54.     (*emdp->texthand)->txSize = emdp->fontsize;
  55.  
  56.     (*emdp->texthand)->clikLoop = (ProcPtr) ClickLoop;
  57.  
  58.     nullrect.top = nullrect.left = nullrect.bottom = nullrect.right = 0;
  59.     tesetsel( (long) 0, (long) 0, emdp->texthand);
  60.     TEKey(BS, emdp->texthand);
  61.         /* fix TE cursor positioning problem--strange but true! */
  62.  
  63.     /* add Hornig scrollbar */
  64.     sBarRect = emdp->textwindow->portRect;
  65.     InsetRect(&sBarRect, -1, -1 );
  66.     sBarRect.left = sBarRect.right - SBARWIDTH;
  67.     sBarRect.bottom -= (SBARWIDTH - 1);            /* space for grow zone */
  68.     emdp->vBarHand = NewControl( emdp->textwindow, &sBarRect, "", (Boolean) FALSE,
  69.                             0, 0, ScrollMax(emdp), scrollBarProc, 0L );
  70.  
  71.     SetPort(emwindow);
  72. }
  73.  
  74.  
  75. /* set the width and fontsize of the text window.  hsize is the emulator area width */
  76.  
  77. textwsize(hsize, vsize)
  78. int hsize;
  79. int vsize;
  80. {
  81.     TEHandle texthand;
  82.     FontInfo  finfo;
  83.     TERec * textptr;
  84.     GrafPtr oport;
  85.     Rect nviewrect;
  86.     Rect sBarRect;
  87.  
  88.     GetPort(&oport);
  89.     SetPort(emdp->textwindow);
  90.  
  91.     HLock(emdp->texthand);
  92.     texthand = emdp->texthand;
  93.     textptr = *texthand;
  94.  
  95.     TextFont(emdp->normfont);
  96.     TextSize(emdp->fontsize);
  97.     
  98.     GetFontInfo(&finfo);
  99.     textptr->fontAscent = finfo.ascent + finfo.leading;
  100.     textptr->lineHeight = textptr->fontAscent + finfo.descent; 
  101.  
  102.     EraseRect(&emdp->textwindow->portRect);
  103.  
  104. #ifndef SIZETEXTWINDOW
  105.     /* now we just use the given size */
  106.     hsize += SBARWIDTH + 2 * TEXTINSET;            /* textwindow is a bit larger... */
  107.     vsize = (textptr->lineHeight * emdp->linecount) + (2 * TEXTINSET);    
  108.         make same height as emulator */
  109.         /* was emdp->textwindow->portRect.bottom - emdp->textwindow->portRect.top, */
  110. #endif
  111.     SizeWindow(emdp->textwindow, hsize, vsize, (Boolean) FALSE);
  112.  
  113.     InvalRect(&emdp->textwindow->portRect);
  114.         /* invalidate the whole window */
  115.         
  116.     textptr->txSize = (short) emdp->fontsize;
  117.  
  118.     /* reset text to top */
  119.     emdp->FirstLine = 0;
  120.  
  121.     /* only set certain TE vars or TE gets confused about where the text is */
  122. #ifdef OLDDESTRECT
  123.     textptr->destRect.top = TEXTINSET;
  124.     textptr->destRect.right = thePort->portRect.right - 20;
  125.  
  126.     /* reset the # of lines and the view rect */
  127.     emdp->textlines = ((thePort->portRect.bottom - TEXTINSET) / textptr->lineHeight );
  128.  
  129.     textptr->viewRect.bottom = TEXTINSET + emdp->textlines * textptr->lineHeight;
  130.         /* round height of view rect to even bit multiple of font size */
  131.     textptr->viewRect.right = thePort->portRect.right - 20;
  132.  
  133. #else
  134.     
  135.     textptr->destRect.top = TEXTINSET;
  136.     textptr->destRect.right = thePort->portRect.right - 22;
  137.  
  138.     setteview(&nviewrect);
  139.     textptr->viewRect.bottom = nviewrect.bottom;
  140.     textptr->viewRect.right = nviewrect.right;
  141. #endif
  142.  
  143.     HideControl(emdp->vBarHand);
  144.     sBarRect = emdp->textwindow->portRect;
  145.     InsetRect(&sBarRect, -1, -1 );
  146.     sBarRect.left = sBarRect.right - SBARWIDTH;
  147.     sBarRect.bottom -= (SBARWIDTH - 1);                    /* space for grow zone */
  148.     MoveControl(emdp->vBarHand, sBarRect.left, sBarRect.top); 
  149.  
  150.     SizeControl(emdp->vBarHand, sBarRect.right - sBarRect.left, 
  151.         sBarRect.bottom - sBarRect.top);
  152.         
  153.     HUnlock(emdp->texthand);
  154.     
  155. #ifdef SIZETEXTWINDOW
  156.     TECalText(emdp->texthand);
  157.     InvalRect(&(*emdp->texthand)->viewRect);
  158. #endif
  159.  
  160.     textctlupd(emdp);
  161.     SelView(emdp);
  162.     ShowControl(emdp->vBarHand);
  163.  
  164.     SetPort(oport);
  165. }
  166.  
  167.  
  168.  
  169. textwmove(twp, hshift, vshift)
  170. struct winds * twp;
  171. short hshift;
  172. short vshift;
  173. {
  174.     Point textpoint;
  175.     GrafPtr oport;
  176.     
  177.     GetPort(&oport);
  178.     SetPort(twp->textwindow);
  179.     
  180.     textpoint.v = twp->textwindow->portRect.top;
  181.     textpoint.h = twp->textwindow->portRect.left;
  182.     LocalToGlobal(&textpoint);
  183.     
  184.     MoveWindow(twp->textwindow, textpoint.h + hshift, textpoint.v + vshift, (Boolean) FALSE);
  185.     SetPort(oport);
  186. }
  187.  
  188.  
  189. /* append text to the emdp textwindow without disturbing selection */
  190.  
  191. textwappend(textp, length)
  192. unsigned char * textp;
  193. long length;
  194. {
  195.     long selstart;
  196.     long selend;
  197.     long startlength;
  198.     
  199.     register unsigned char * charp;
  200.     register unsigned char * stakep;
  201.     register long chlen;
  202.     
  203.     if (! memtest(length, "to append text"))
  204.         /* out of memory */
  205.         return(-1);
  206.     
  207.     selstart = (*emdp->texthand)->selStart;
  208.     selend = (*emdp->texthand)->selEnd;
  209.     startlength = (*emdp->texthand)->teLength;
  210.     
  211.     if ((unsigned long) (startlength + length) > 32500L) {
  212.         short * linestart;
  213.         short linecount;
  214.         short nlines;
  215.         
  216.         nlines = (*emdp->texthand)->nLines;
  217.         linestart = &(*emdp->texthand)->lineStarts[0];
  218.         linecount = 0;
  219.         
  220.         while (*linestart < length) {
  221.             /* delete a page at a time */
  222.             linecount += emdp->linecount;
  223.             if (linecount >= nlines) {
  224.                 error("Can't append text to Edit window");
  225.                 return;
  226.             }
  227.             linestart += emdp->linecount;
  228.             
  229.         }
  230.         TESetSelect((long) 0, (long) *linestart, emdp->texthand);
  231.         TEDelete(emdp->texthand);
  232.     }
  233.     
  234.     tesetsel( (long) (*emdp->texthand)->teLength, (long) (*emdp->texthand)->teLength, emdp->texthand);
  235. #ifdef NODIACRITICS
  236.     TEInsert(textp, (long) length, emdp->texthand);
  237. #else
  238.     /* for diacritics to be represented properly, TEKey() must be called */
  239.     stakep = charp = textp;
  240.     
  241.     for (chlen = 0; length--; charp++) {
  242.         if (isdiacritic[*charp]) {
  243.             /* TEKey has to be used to input diacritics properly;
  244.                 must be using default font */
  245.             if (chlen) {
  246.                 TEInsert(stakep, (long) chlen, emdp->texthand);
  247.                 chlen = 0;
  248.             }
  249.             TEKey(*charp, emdp->texthand);
  250.             stakep = charp + 1;
  251.         }
  252.         else
  253.             chlen++;
  254.     }
  255.     if (chlen) {
  256.         /* there still remain some characters at the end */
  257.         TEInsert(stakep, (long) chlen, emdp->texthand);
  258.     }
  259. #endif
  260.     /* reset the selection */
  261.     if (selstart != startlength)
  262.         /* only reset cursor if it was not at the end of the text */
  263.         tesetsel( (long) selstart, (long) selend, emdp->texthand);
  264.     textctlupd(emdp);
  265.     if (selstart == startlength)
  266.         /* scroll automatically if the cursor was at the end of the text */
  267.         SelView(emdp);
  268. }
  269.  
  270.  
  271. tesetsel(start, end, tehand)
  272. long start;
  273. long end;
  274. TEHandle tehand;
  275. {
  276.     (*tehand)->clikStuff = 255;
  277.         /* gruesome TE botch requires one to do this to get cursor at beginning
  278.             of line 
  279.         */
  280.     TESetSelect(start, end, tehand);
  281. }
  282.  
  283. /* here follow routines lifted from Doug Hornig's LocalEdit.c */
  284.  
  285. /*  ClickLoop is called repeatedly while the mouse button is down during editing.
  286.  *  It checks if the mouse is above or below the view rectangle and performs
  287.  *  automatic scrolling if it is.
  288.  */
  289.  
  290. /* kevin: changed from pascal Boolean to long */
  291.  
  292. pascal Boolean ClickLoop()
  293. {
  294.     Rect        view;
  295.     Point        mouse;
  296.     int            PrevFirstLine;
  297.     RgnHandle    PrevClip;
  298.  
  299. /* save regs first kevin--added from my own TE code; is this really necessary? */
  300.  
  301.     view = (**keydp->texthand).viewRect;        /* get the TE view rect */
  302.     PrevFirstLine = keydp->FirstLine;
  303.     GetMouse( &mouse );                /* get mouse loc in local coords */
  304.  
  305.     if( mouse.v > view.bottom && keydp->FirstLine < ScrollMax(keydp) )
  306.         ScrollToLine(keydp, keydp->FirstLine + 1 );    /* below the bottom */
  307.  
  308.     if( mouse.v < view.top && keydp->FirstLine > 0 )
  309.         ScrollToLine(keydp,  keydp->FirstLine - 1 );    /* above the top */
  310.  
  311.     if( keydp->FirstLine != PrevFirstLine ) /* have we scrolled? */
  312.     {                                 /*  then we must draw the scroll bar */
  313.         GetClip        ( PrevClip = NewRgn() );    /*  because clipRgn is modified */
  314.         ClipRect    ( &(**keydp->vBarHand).contrlRect );    /*  during TEClick calls (like now) */
  315.         Draw1Control( keydp->vBarHand );    /* draw the scroll bar */
  316.         SetClip        ( PrevClip );    /* restore the clip region */
  317.         DisposeRgn    ( PrevClip );
  318.     }
  319.  
  320.     return((Boolean) TRUE);
  321. }
  322.  
  323. /* RepAction is called repeatedly by ToolBox TrackControl routine */
  324.  
  325. pascal void RepAction( CtlHand, PartCode )
  326. ControlHandle    CtlHand;
  327. int                PartCode;
  328. {
  329.     int    ScrollFac;
  330.  
  331.     switch( PartCode )
  332.     {
  333.         case inUpButton:
  334.             ScrollFac = -1;
  335.             break;
  336.         case inDownButton:
  337.             ScrollFac =  1;
  338.             break;
  339.         case inPageUp:
  340.             ScrollFac = -keydp->textlines;
  341.             break;
  342.         case inPageDown:
  343.             ScrollFac =  keydp->textlines;
  344.             break;
  345.         default:
  346.             return;
  347.     }
  348.  
  349.     ScrollToLine(keydp, max( 0, min( keydp->FirstLine + ScrollFac, ScrollMax(keydp) ) ) );
  350. }
  351.  
  352. /*  Move Elevator is called after the scroll bar 'thumb' is moved */
  353.  
  354. MoveElevator( CtlHand )
  355. ControlHandle    CtlHand;
  356. {
  357.     ScrollToLine(keydp, GetCtlValue( CtlHand ) );
  358. }
  359.  
  360. /*  Put theLine at the top of the screen */
  361.  
  362. ScrollToLine(twp, theLine )
  363. struct winds * twp;
  364. int theLine;
  365. {
  366.     TEScroll( 0, twp->lineheight * ( twp->FirstLine - theLine ), twp->texthand );
  367.     SetCtlValue( twp->vBarHand, twp->FirstLine = theLine );
  368. }
  369.  
  370. /*  Make sure the selection range is in view */
  371.  
  372. SelView(twp)
  373. struct winds * twp;
  374. {
  375.     register int NewFirst;    /* line selection starts on */
  376.  
  377. /*  Return the line number that the selection range starts on.
  378.  *  Range is 0 through nLines-1.
  379.  */
  380.  
  381.     static int     PrevCur = 0;
  382.     int             *FrstLine;
  383.     register int *LastLine, *CheckLine;
  384.     register int SelLoc;
  385.     int             NumLines;
  386.  
  387.     /* kevin:  folded in CurLine() routine */
  388.     if( ( NumLines = (**twp->texthand).nLines - 1 ) < 0 ) {
  389.         NewFirst = PrevCur = 0;        /* nLines is sometimes zero */
  390.     }
  391.     else {
  392.         SelLoc      = (**twp->texthand).selStart;
  393.         FrstLine  = (**twp->texthand).lineStarts;
  394.         LastLine  = FrstLine + NumLines;
  395.         CheckLine = FrstLine + min( PrevCur, NumLines );
  396.     
  397.         while( *CheckLine < SelLoc && CheckLine < LastLine )
  398.             CheckLine++;                /* check lineStarts after previous curline */
  399.     
  400.         while( *CheckLine > SelLoc )
  401.             CheckLine--;                /* then check lineStarts before it */
  402.     
  403.         NewFirst = PrevCur = CheckLine - FrstLine;
  404.     }
  405.     if( NewFirst < twp->FirstLine ) {
  406.         /* kevin: replaced             ScrollToLine( NewFirst ); which uses keydp */
  407.  
  408.         ScrollToLine(twp, NewFirst );
  409.     }
  410.     else if( ( NewFirst -= (twp->textlines - 1) ) > twp->FirstLine ) {
  411.         ScrollToLine(twp, NewFirst );
  412.     }
  413. }
  414.  
  415. /*  ScrollMax is used to calculate the maximum scroll bar setting */
  416.  
  417. int  ScrollMax(twp)
  418. struct winds * twp;
  419. {
  420.     return( max( twp->FirstLine, (**twp->texthand).nLines - (twp->textlines) ) );
  421. }
  422.  
  423.  
  424.  
  425. int min( v1, v2 )
  426. register int v1, v2;
  427. {
  428.     return( v1 < v2 ? v1 : v2 );
  429. }
  430.  
  431. int max( v1, v2 )
  432. register int v1, v2;
  433. {
  434.     return( v1 > v2 ? v1 : v2 );
  435. }
  436.  
  437.  
  438. /*     textwunwrap attempts to convert the text in TextHand from -mainframe- format
  439.  *  to -TextEdit- format.  That means changing the returns at the end of lines
  440.  *  that should be wrapped into spaces.
  441.  */
  442.  
  443. textwunwrap(twp)
  444. struct winds * twp;
  445. {
  446.     register char prev, this, next, *cPtr;
  447.     register int  theLen;
  448.     register int charcount = 0;
  449.     register int selstart = (*twp->texthand)->selStart;
  450.     register int selend = (*twp->texthand)->selEnd;
  451.     GrafPtr oport;
  452.     
  453.     GetPort(&oport);
  454.     if ( ( theLen = (*twp->texthand)->teLength ) == 0 )
  455.         return;                        /* zero length text */
  456.  
  457.     SetPort(twp->textwindow);
  458.     if (selstart == selend) {
  459.         /* if no selection, convert the whole TE text */
  460.         selstart = 0;
  461.         selend = theLen;
  462.     }
  463.     cPtr = *(*twp->texthand)->hText;
  464.     prev = ' ';                        /* load initial characters */
  465.     this = *cPtr++;
  466.     next = *cPtr;
  467.     
  468.     while( ++charcount < theLen )                /* loop though the whole text */
  469.     {
  470.         /* only convert the selection range */
  471.         if (charcount < selstart) {
  472.             ++cPtr;        
  473.             continue;
  474.         }
  475.         if (charcount > selend)
  476.              break;
  477.              
  478.         if ( this == '\r' )    {    
  479.             /* a return, check to see if it should be replaced with a space */
  480.             if (  ! (  prev == '\r'  
  481.  
  482.                     || next == ' ' 
  483.                     || next == TAB 
  484.                     || next == '\r'
  485.                 ) 
  486.             ) {
  487.                 /* there are non-space characters around it, replace it with a space */
  488.                 *(cPtr - 1) = ' ';    
  489.             }
  490.         }
  491.         prev = this;                /* shift the chars over */
  492.         this = next;
  493.         next = *++cPtr;
  494.     }
  495.     TECalText(twp->texthand);
  496.     InvalRect(&(*twp->texthand)->viewRect);
  497.  
  498.     textctlupd(twp);
  499.     SelView(twp);
  500.     SetPort(oport);
  501. }
  502.  
  503. /*  textwwrap performs the opposite function that textwunwrap does.  It puts return
  504.  *  characters at the end of each line that is wrapped by TextEdit.
  505.  */
  506.  
  507. textwwrap(twp)
  508. struct winds * twp;
  509. {
  510.     register int  *lStart  = (*twp->texthand)->lineStarts;
  511.     register char *theText = *(*twp->texthand)->hText;
  512.     register int  lCount   = (*twp->texthand)->nLines;
  513.     register short crpos;
  514.     register int selstart = (*twp->texthand)->selStart;
  515.     register int selend = (*twp->texthand)->selEnd;
  516.     int textlen;
  517.     
  518.     textlen = (*twp->texthand)->teLength; 
  519.     if (textlen == 0)
  520.         return;                        /* zero length text */
  521.  
  522.     if (selstart == selend) {
  523.         /* if no selection, convert the whole TE text */
  524.         selstart = 0;
  525.         selend = textlen;
  526.     }
  527.     while( --lCount > 0) {
  528.         /* only convert the selection range */
  529.         crpos = *++lStart;
  530.         if (crpos < selstart)        
  531.             continue;
  532.         if (crpos > selend)
  533.              break;
  534.         theText[ crpos - 1 ] = '\r';    /* put a return at each EOL */
  535.     }
  536.     /* no need to update, because the appearance is unchanged */
  537. }
  538.  
  539. /* end of Hornig routines */
  540.  
  541. textctlupd(twp)
  542. struct winds * twp;
  543. {
  544.     SetCtlMax( twp->vBarHand, ScrollMax(twp) );        /* make sure scroll bar max is correct */
  545.     SetCtlValue( twp->vBarHand, twp->FirstLine );    /* and the thumb is in the right place */
  546. }
  547.  
  548.  
  549. /* cut text from a text window */
  550.  
  551. textwcut(twp)
  552. struct winds * twp;
  553. {
  554.     twp->textscrapped = TRUE;
  555.     SelView(twp);                    /* guarantee FirstLine won't change */
  556.     TECut(twp->texthand);
  557.     textctlupd(twp);
  558. }
  559.  
  560. /* cut text from a text window */
  561.  
  562. textwclear(twp)
  563. struct winds * twp;
  564. {
  565.     SelView(twp);                    /* guarantee FirstLine won't change */
  566.     TEDelete(twp->texthand);
  567.     textctlupd(twp);
  568. }
  569.  
  570. /* copy text from a text window */
  571.  
  572. textwcopy(twp)
  573. struct winds * twp;
  574. {
  575.     long len;
  576.     
  577.     twp->textscrapped = TRUE;
  578.     len = (*twp->texthand)->selEnd - (*twp->texthand)->selStart;
  579.     if (memtest(len, copyerr)) {
  580.         TECopy(twp->texthand);
  581.     }
  582. }
  583.  
  584.  
  585. /* paste text into a text window */
  586.  
  587. textwpaste(twp)
  588. struct winds * twp;
  589. {
  590.     long len;
  591.     
  592.     len = TEScrLen - 
  593.         ((*twp->texthand)->selEnd - (*twp->texthand)->selStart);
  594.  
  595.     if (len < 0 || memtest(len, copyerr)) {
  596.         /* might be smaller than before... */
  597.         SelView(twp);                    /* guarantee FirstLine won't change */
  598.         TEPaste(twp->texthand);
  599.         textctlupd(twp);
  600.         SelView(twp);
  601.     }
  602. }
  603.  
  604. #define FILECOMPAT
  605. #ifdef FILECOMPAT
  606. /* all Aztec C file routines blow the resource fork away, and must 
  607.     be changed to use Mac routines */
  608.  
  609. /* if the filename is the same as the session name, save the text 
  610.     buffer in the file before an upload takes place
  611. */
  612.  
  613. textupedit(filename)
  614. char * filename;
  615. {
  616.     FILE *textfp;
  617.     int writecount;
  618.     char filebuffer[514];
  619.     unsigned short textlength;
  620.     char macfile[256];
  621.  
  622.     if (!emdp->editload)
  623.         return(-1);
  624.  
  625.     GetWTitle(emdp->textwindow, &macfile[0]);
  626.     ptoc(&macfile[0]);
  627.      if (strcmp(filename, &macfile[0]) == 0) {
  628.         /* the filename matches the text window name "SESSIONNAME.edit", go for it */
  629.         /* save the text buffer in the file */
  630.         
  631.         if (emdp->editupwrap)
  632.             textwwrap(emdp);        /* wrap text with Carriage Returns first */
  633.         
  634.         HLock((*emdp->texthand)->hText);
  635.         
  636.         textlength = (*emdp->texthand)->teLength;
  637.         textfp = fopen(filename, "w");
  638.         if (textfp != NULL) { 
  639.             writecount = fwrite(*(*emdp->texthand)->hText, 1, textlength, textfp);
  640.             if (writecount != textlength) {
  641.                 error("Can't save whole text into upload file");
  642.             }
  643.             fclose(textfp);
  644.         }
  645.         else
  646.             error("Can't open upload file to save text");
  647.  
  648.         HUnlock((*emdp->texthand)->hText);
  649.     }
  650.     return(0);
  651. }
  652.  
  653.  
  654. /* if the filename is the same as the session name, load it into the text 
  655.     buffer
  656. */
  657.  
  658. textdownedit(filename)
  659. char * filename;
  660. {
  661.     char macfile[256];
  662.  
  663.     if (!emdp->editload)
  664.         return(-1);
  665.  
  666.     GetWTitle(emdp->textwindow, &macfile[0]);
  667.     ptoc(&macfile[0]);
  668.      if (strcmp(filename, &macfile[0]) == 0) {
  669.         /* the filename matches "SESSIONNAME.edit", go for it */
  670. #ifdef DOWNDELETE
  671.         /* we probably don't want to automatically delete the current text */
  672.         /* first delete the current text */
  673.         tesetsel( (long) 0, (long) (*emdp->texthand)->teLength, emdp->texthand);
  674.         TEDelete(emdp->texthand);
  675.         textctlupd(emdp);
  676.         SelView(emdp);
  677. #endif        
  678.         textwload(filename);
  679.         if (emdp->editdownwrap)
  680.             textwunwrap(emdp);    
  681.                 /* eliminate most Carriage Returns in text */
  682.     }
  683.     return(0);
  684. }
  685.  
  686. /* append a file to the .edit window */
  687.  
  688. textwload(filename) 
  689. char *filename;
  690. {
  691.     FILE *textfp;
  692.     int readcount;
  693.     long readtotal;
  694.     char filebuffer[514];
  695.  
  696.     textfp = fopen(filename, "r");
  697.     if (textfp != NULL) { 
  698.         readtotal = 0;
  699.         while (TRUE) {
  700.             readcount = fread(&filebuffer[0], 1, 512, textfp);
  701.             readtotal += readcount;
  702.             if (readcount == 0) {
  703.                 /* we've read the whole file or can't read any more */
  704.                 break;
  705.             }
  706.             textwappend(&filebuffer[0], (long) readcount);
  707.         }
  708.         fclose(textfp);
  709.         if (readtotal > 32500) 
  710.             error("Couldn't read the whole file into .edit (> 32,500 characters)");
  711.         putaction(RSLT_EMC, EM_EDIT);    /* bring up the edit window */
  712.     }
  713.     else
  714.         error("Can't load file into text window");
  715. }
  716.  
  717. #else
  718.     /* are file compatibility routines in place ? */
  719.  
  720. textupedit()
  721. {
  722. }
  723.  
  724. textdownedit()
  725. {
  726. }
  727.  
  728. #endif
  729.  
  730. #else
  731.     /* not USETEXTWINDOWS */
  732. textwinit()
  733. {
  734. }
  735.  
  736. textwsize()
  737. {
  738. }
  739.  
  740. /* no text windows, do nothing */
  741.  
  742. textupedit()
  743. {
  744. }
  745.  
  746. textdownedit()
  747. {
  748. }
  749.  
  750. /* when text windows are disabled, append operations go into the clipboard */
  751.  
  752. textwappend(textp, length)
  753. char * textp;
  754. long length;
  755. {
  756.     puttextscrap(textp, length);
  757. }
  758.  
  759.  
  760. textctlupd(twp)
  761. struct winds * twp;
  762. {
  763. }
  764.  
  765.  
  766. textwcopy(twp)
  767. struct winds * twp;
  768. {
  769. }
  770.  
  771. textwpaste(twp)
  772. struct winds * twp;
  773. {
  774. }
  775.  
  776.  
  777. textwcut(twp)
  778. struct winds * twp;
  779. {
  780. }
  781.  
  782. textwwrap(twp)
  783. struct winds * twp;
  784. {
  785. }
  786.  
  787. textwunwrap(twp)
  788. struct winds * twp;
  789. {
  790. }
  791.  
  792. tesetsel()
  793. {
  794. }
  795.  
  796. #endif
  797.  
  798. /* set the selection to the end of the text and jump to it */
  799.  
  800. textwgotoend(twp)
  801. struct winds * twp;
  802. {
  803.     tesetsel( (long) (*twp->texthand)->teLength, 
  804.         (long) (*twp->texthand)->teLength, 
  805.         twp->texthand);
  806.     ScrollToLine(twp, ScrollMax(twp));
  807. }
  808.  
  809.  
  810. #ifdef USETEXTWINDOWS
  811. /* append the keymap to the text window */
  812.  
  813. #define XTEXT    500
  814. #define NEG (-1)
  815.  
  816. char kxappstart[] = "\r\rKey Macro list:\r";
  817. char kxappend[] = "\r\rEnd of Key Macro list\r\r";
  818.  
  819. keyxappend()
  820. {
  821.     TEHandle texthand = keydp->texthand;
  822.     long length;
  823.     unsigned char thetext[XTEXT + 6];
  824.     EventRecord anevent;
  825.     struct keyxlist * keyxp;
  826.     long keyxid;
  827.     short dkeycode, modifiers;
  828.     unsigned char * actptr;
  829.     unsigned char * textend;
  830.     struct token * keyact;
  831.     int count;
  832.     
  833.     getcontext(keydp);            /* textwappend() uses emdp */
  834.     
  835.     strcpy(&thetext[0], "\r\t");
  836.         /* a carriage  return & tab starts off the line */
  837.     textwappend(&kxappstart[0], (long) strlen(&kxappstart[0]));
  838.     
  839.     for (keyxp = keydp->keyxhead; keyxp != NULL; keyxp = keyxp->nextkey) {
  840.         keyxid = ((struct keyactlist *) (*keyxp->hkeyact))->keyid;
  841.  
  842.         modifiers = ((keyxid >> 16) & 0xffff);
  843.         dkeycode = (keyxid & 0xffff) >> 8;
  844.  
  845.         /* now dump the codes for it */
  846.         count = keyxp->actlen;
  847.         keyact = &((struct keyactlist *) (*keyxp->hkeyact))->act[0];
  848.         actptr = &thetext[2];
  849.         
  850.         for (textend = &thetext[2] + XTEXT; count--; keyact++) {
  851.             if ( (length = actdecode(actptr, textend, keyact, FALSE)) == NEG)
  852.                 /* error decoding--should alert that at end? */
  853.                 break;
  854.             else
  855.                 actptr += length;
  856.         }
  857.         
  858.         length = actptr - &thetext[2];
  859.         
  860.         *actptr++ = ' ';            
  861.         /* make sure diacritic has something nice to sit on */
  862.         *actptr++ = TAB;
  863.             /* add a tab for formatting */
  864.             
  865.         /* give the key a name */
  866.         namekey(actptr, dkeycode, modifiers);
  867.         actptr += strlen(actptr);
  868.  
  869.         if (length == 1) {
  870.             /* if the code was just a single character, give decimal equivalent also */
  871.             *actptr++ = TAB;
  872.             *actptr++ = '\\';
  873.             dectrans(actptr, thetext[2]);
  874.             actptr += 3;    /* 3 characters just added... */
  875.         }
  876.         
  877.         length = actptr - &thetext[0];
  878.  
  879.         if (! memtest(length, "to dump key macros"))
  880.             /* out of memory */
  881.             break;
  882.         
  883.         textwappend(&thetext[0], (long) length);
  884.             /* starts with 0 to insert a CR */
  885.  
  886.     }
  887.     textwappend(&kxappend[0], (long) strlen(&kxappend[0]));
  888. }
  889.  
  890.  
  891. #endif
  892. /* 
  893.  *  display text in a text window; both are taken from resource file, with the 
  894.  *  assumption the id number is the same for both
  895.  */
  896.  
  897. helptextwindow(resid)
  898. {
  899.     long length;
  900.     Handle thetext;
  901.  
  902.     thetext = GetResource('TEXT', (short) resid);
  903.     if (thetext == NULL)
  904.         return(-1);
  905.         
  906.     getcontext(keydp);        /* textwappend uses emdp */
  907.     
  908.     HLock(thetext);
  909.     length = GetHandleSize(thetext);
  910.  
  911.     textwappend(*thetext + 4, (long) (length - 4));
  912.         /* TEXT types have 4 bytes of length in them */
  913.     HUnlock(thetext);
  914. }
  915.  
  916.  
  917. /* set the textedit view rectangle, 
  918.     assumes
  919.     portRect.top == 0 
  920.     textedit lineHeight == fontsize
  921. */
  922.  
  923. setteview(viewrect)
  924. Rect * viewrect;
  925. {
  926.     FontInfo  finfo;
  927.     int lineheight;
  928.     
  929.     GetFontInfo(&finfo);
  930.     lineheight = finfo.ascent + finfo.descent + finfo.leading;
  931.  
  932.     emdp->textlines = 
  933.         ((thePort->portRect.bottom - thePort->portRect.top - TEXTINSET - 4) 
  934.                 / lineheight );
  935.  
  936.     viewrect->top = TEXTINSET;
  937.     viewrect->left = thePort->portRect.left;
  938.     viewrect->bottom = viewrect->top + emdp->textlines * lineheight;
  939.         /* round height of view rect to even bit multiple of font size */
  940.     viewrect->right = thePort->portRect.right - 16;
  941. }
  942.  
  943.  
  944. /* set the textedit destination rectangle which sets wrap boundaries */
  945.  
  946. settedest(destrect)
  947. Rect * destrect;
  948. {
  949.     destrect->top = TEXTINSET;
  950.     destrect->left = TEXTINSET;
  951.     destrect->bottom = thePort->portRect.bottom - thePort->portRect.top;
  952.     destrect->right = thePort->portRect.right - 20 - (2 * emdp->hoffset);
  953. }    
  954.  
  955.  
  956. #ifdef USETEXTWINDFIND
  957.  
  958. /* this routine finds a string in a TextEdit record */
  959.  
  960. #define FINDMAX    1024
  961. #define FORWARD     1
  962. #define BACKWARD    2
  963.  
  964. char fstring[FINDMAX];
  965.  
  966. findstring(texthand, foundat, dir)
  967. TEHandle     texthand;
  968. long *     foundat;
  969. int dir;
  970. {
  971.     char * text;
  972.     int start;
  973.     int end;
  974.     int length;
  975.     int count;
  976.     int offset;
  977.     int skip;
  978.  
  979.     count = strlen(&fstring[0]);    /* TODO should be eliminated */
  980.  
  981.     text = *(*texthand)->hText; 
  982.     start = (*texthand)->selStart;
  983.     end = (*texthand)->selEnd;
  984.     length = (*texthand)->teLength;
  985.     skip = (start == end) ? 0 : 1;
  986.     if (dir == FORWARD) {
  987.         if ((offset = match(fstring, text + start + skip, text + length, dir)) >= 0) {
  988.             *foundat = start + skip + offset;
  989.             return(count);
  990.         }
  991.         /* Not found on first try; wrap and search to initial position */
  992.         if ((offset = match(fstring, text, text + start + count, dir)) >= 0) {
  993.             *foundat = offset;
  994.             return(count);
  995.         }
  996.     }
  997.     else {
  998.         if ((offset = match(fstring, text, text + start, dir)) >= 0) {
  999.             *foundat = offset;
  1000.             return(count);
  1001.         }
  1002.         /* Not found on first try; wrap and search to initial position */
  1003.         if ((offset = match(fstring, text + start, text + length, dir)) >= 0) {
  1004.             *foundat = start + offset;
  1005.             return(count);
  1006.         }
  1007.     }
  1008.     /* no match */
  1009.     return(0);
  1010. }
  1011.  
  1012. /* find a match, returning the offset from the start value */
  1013.  
  1014. match(string, startp, endp, dir)
  1015. char * string;
  1016. register char * startp;
  1017. register char * endp;
  1018. int dir;
  1019. {
  1020.     register int count;
  1021.     register int total;
  1022.     register char * strp;
  1023.     register char * fstrp;
  1024.  
  1025.     count = 0;
  1026.     total = strlen(string);
  1027.     if (dir == FORWARD) {
  1028.         /* search to end */
  1029.         strp = startp;
  1030.         for (fstrp = string; strp < endp; strp++)  {
  1031.             if (*fstrp == *strp) {        
  1032.                 /* contents equal, try next match */
  1033.                 if (++count == total)  {
  1034.                     /* search succeeds, return offset from start */
  1035.                     return(strp - startp - count + 1);
  1036.                 }
  1037.                 fstrp++;
  1038.                 continue;
  1039.             }
  1040.             else {
  1041.                 /* a number of matches have failed */
  1042.                 fstrp = string;
  1043.                 strp -= count;
  1044.                 count = 0;
  1045.             }
  1046.         }
  1047.     }
  1048.     else {
  1049.         /* search backwards */
  1050.         strp = endp;
  1051.         fstrp = string + total - 1;
  1052.             /* on last character in string */
  1053.         while (--strp >= startp)  {
  1054.             if (*fstrp == *strp) {
  1055.                 /* contents equal, try next match */
  1056.                 --fstrp;
  1057.                 if (++count == total)  {
  1058.                     /* search succeeds, return offset from start */
  1059.                     return(strp - startp);
  1060.                 }
  1061.                 continue;
  1062.             }
  1063.             else {
  1064.                 /* a number of matches have failed to pan out */
  1065.                 fstrp = string + total - 1;
  1066.                 strp += count;
  1067.                 count = 0;
  1068.             }
  1069.         }
  1070.     }
  1071.     return(-1);
  1072. }
  1073.  
  1074.  
  1075. textncopy(source, destination, len, maxlen)
  1076. char * source;
  1077. char * destination;
  1078. int len;
  1079. register int maxlen;                /* maximum length in destination */
  1080. {
  1081.     register char * srcp;
  1082.     register char * destp;
  1083.     register char * endpos;
  1084.     register int count;
  1085.  
  1086.     count = 0;
  1087.     srcp = source;
  1088.     destp = destination;
  1089.     for (endpos = srcp + len; srcp < endpos; destp++, srcp++) {
  1090.         *destp = *srcp;
  1091.         if (++count >= maxlen) {
  1092.             /* we can't move the whole thing */
  1093.             *destp = '\0';
  1094.             return(-1);
  1095.         }
  1096.     }
  1097.     *destp = '\0';
  1098. }
  1099.  
  1100.  
  1101. #endif
  1102.  
  1103.